﻿using System.Collections.Generic;
using System;
using System.Drawing;
using System.Collections;
using System.Runtime.InteropServices;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Data.OleDb;
using shptxt;
using System.Windows.Forms;
using System.Reflection;

namespace shptxt
{
    public enum GISMapActions
    {
        zoomin, zoomout,
        moveup, movedown, moveleft, moveright
    };

    public enum SHAPETYPE
    {
        point = 1,
        line = 3,
        polygon = 5
    };

    public class GISField
    {
        public Type datatype; //表示字段的数据类型
        public string name; //表示字段的名称
        public GISField(Type _dt, string _name)
        {
            datatype = _dt;
            name = _name;
        }
    }

    public class GISTools
    {
        public static Point[] GetScreenPoints(List<GISVertex> _vertexes, GISView view)
        {
            Point[] points = new Point[_vertexes.Count];
            for (int i = 0; i < points.Length; i++)
            {
                points[i] = view.ToScreenPoint(_vertexes[i]);
            }
            return points;
        }

        public static GISVertex CalculateCentroid(List<GISVertex> _vertexes)
        {
            if (_vertexes.Count == 0) return null;
            double x = 0;
            double y = 0;
            for (int i = 0; i < _vertexes.Count; i++)
            {
                x += _vertexes[i].x;
                y += _vertexes[i].y;
            }
            return new GISVertex(x / _vertexes.Count, y / _vertexes.Count);
        }

        public static GISExtent CalculateExtent(List<GISVertex> _vertexes)
        {
            if (_vertexes.Count == 0) return null;
            double minx = Double.MaxValue;
            double miny = Double.MaxValue;
            double maxx = Double.MinValue;
            double maxy = Double.MinValue;
            for (int i = 0; i < _vertexes.Count; i++)
            {
                if (_vertexes[i].x < minx) minx = _vertexes[i].x;
                if (_vertexes[i].x > maxx) maxx = _vertexes[i].x;
                if (_vertexes[i].y < miny) miny = _vertexes[i].y;
                if (_vertexes[i].y > maxy) maxy = _vertexes[i].y;
            }
            return new GISExtent(minx, maxx, miny, maxy);
        }

        public static double CalculateLength(List<GISVertex> _vertexes)
        {
            double length = 0;
            for (int i = 0; i < _vertexes.Count - 1; i++)
            {
                length += _vertexes[i].Distance(_vertexes[i + 1]);
            }
            return length;
        }

        public static double CalculateArea(List<GISVertex> _vertexes)
        {
            double area = 0;
            for (int i = 0; i < _vertexes.Count - 1; i++)
            {
                area += VectorProduct(_vertexes[i], _vertexes[i + 1]);
            }
            area += VectorProduct(_vertexes[_vertexes.Count - 1], _vertexes[0]);
            return area / 2;
        }

        public static double VectorProduct(GISVertex v1, GISVertex v2)
        {
            return v1.x * v2.y - v1.y * v2.x;
        }
    }

    public class GISLayer
    {
        public string Name; //图层名称
        public GISExtent Extent; //图层范围
        public bool DrawAttributeOrNot; //是否绘制图层
        public int LabelIndex; //标签索引
        public SHAPETYPE ShapeType; //图层的要素属性
        public List<GISFeature> Features = new List<GISFeature>(); //图层包含的所有要素列表
        public List<GISField> Fields; //图层包含的所有属性字段的列表

        public GISLayer(string _name, SHAPETYPE _shapetype, GISExtent _extent, List<GISField> _fields)
        {
            Name = _name;
            ShapeType = _shapetype;
            Extent = _extent;
            Fields = _fields;
        }

        public GISLayer(string _name, SHAPETYPE _shapetype, GISExtent _extent)
        {
            Name = _name;
            ShapeType = _shapetype;
            Extent = _extent;
            Fields = new List<GISField>();
        }

        public void draw(Graphics graphics, GISView view)
        {
            for (int i = 0; i < Features.Count; i++)
            {
                Features[i].draw(graphics, view, DrawAttributeOrNot, LabelIndex);
            }
        }
        public void AddFeature(GISFeature feature) //向图层中添加一个要素
        {
            Features.Add(feature);
        }
        public int FeatureCount() //获取图层中要素的数量
        {
            return Features.Count;
        }
        public GISFeature GetFeature(int i) //获取图层中指定索引位置的要素
        {
            return Features[i];
        }
    }

    public class GISTXT
    {
        //输出
        public static void Exporttxt(GISLayer layer,string filepath)
        {
            if (layer.ShapeType == SHAPETYPE.point)
            {
                filepath = filepath.Replace(".shp", ".txt");
                StreamWriter ly = new StreamWriter(filepath);
                ly.WriteLine("{0}", layer.ShapeType.ToString());
                ly.WriteLine("{0}", layer.Extent.bottomleft.x.ToString());
                ly.WriteLine("{0}", layer.Extent.bottomleft.y.ToString());
                ly.WriteLine("{0}", layer.Extent.upright.x.ToString());
                ly.WriteLine("{0}", layer.Extent.upright.y.ToString());
                foreach (GISFeature feature in layer.Features)
                {
                    ly.WriteLine("{0},{1},{2}", feature.spatialpart.centroid.x.ToString(), feature.spatialpart.centroid.y.ToString(), feature.attributepart.GetValue(1));
                }
                ly.Close();
            }
            else if (layer.ShapeType == SHAPETYPE.line)
            {
                filepath = filepath.Replace(".shp", ".txt");
                StreamWriter li = new StreamWriter(filepath);
                li.WriteLine("{0}", layer.ShapeType.ToString());
                li.WriteLine("{0}", layer.Extent.bottomleft.x.ToString());
                li.WriteLine("{0}", layer.Extent.bottomleft.y.ToString());
                li.WriteLine("{0}", layer.Extent.upright.x.ToString());
                li.WriteLine("{0}", layer.Extent.upright.y.ToString());
                li.WriteLine("{0}", layer.Features.Count); //线实体要素数
                foreach (GISFeature feature in layer.Features) //遍历每个线实体
                {
                    GISLine line = (GISLine)feature.spatialpart;
                    li.WriteLine("{0}", feature.attributepart.GetValue(0)); //线属性
                    li.WriteLine("{0}", line.Vertexes.Count); //点的个数
                    foreach (GISVertex vertex in line.Vertexes) //遍历线实体中的一个点
                    {
                        li.WriteLine("{0},{1}",vertex.x.ToString(),vertex.y.ToString());
                    }
                }
                li.Close();
            }
            else
            {
                filepath = filepath.Replace(".shp", ".txt");
                StreamWriter po = new StreamWriter(filepath);
                po.WriteLine("{0}", layer.ShapeType.ToString());
                po.WriteLine("{0}", layer.Extent.bottomleft.x.ToString());
                po.WriteLine("{0}", layer.Extent.bottomleft.y.ToString());
                po.WriteLine("{0}", layer.Extent.upright.x.ToString());
                po.WriteLine("{0}", layer.Extent.upright.y.ToString());
                po.WriteLine("{0}", layer.Features.Count); //面实体要素数
                foreach(GISFeature feature in layer.Features) //遍历每个面实体
                {
                    GISPolygon poly = (GISPolygon)feature.spatialpart;
                    po.WriteLine("{0}", feature.attributepart.GetValue(0)); //面属性
                    po.WriteLine("{0}", poly.Vertexes.Count); //每个面中点的个数
                    foreach (GISVertex vertex in poly.Vertexes)
                    {
                        po.WriteLine("{0},{1}",vertex.x.ToString(),vertex.y.ToString());
                    }
                }
                po.Close();
            }
        }

        //读取
        public static GISLayer ReadTXT(string filepath,string filename)
        {
            string[] lines = File.ReadAllLines(filepath);
            SHAPETYPE ShapeType = (SHAPETYPE)Enum.Parse(typeof(SHAPETYPE), lines[0]);
            GISVertex bottomleft = new GISVertex(double.Parse(lines[1]), double.Parse(lines[2]));
            GISVertex upright = new GISVertex(double.Parse(lines[3]), double.Parse(lines[4]));
            GISExtent oneextent = new GISExtent(bottomleft, upright);
            GISLayer layer = new GISLayer(filename, ShapeType, oneextent);
            if (ShapeType == SHAPETYPE.point)
            {
                layer.ShapeType = SHAPETYPE.point;
                for (int i = 5; i < lines.Length; i++)
                {
                    string[] pointData = lines[i].Split(',');
                    GISVertex vertex = new GISVertex(double.Parse(pointData[0]), double.Parse(pointData[1]));
                    GISPoint onepoint = new GISPoint(vertex);
                    onepoint.extent = layer.Extent;
                    GISAttribute oneattribute = new GISAttribute();
                    oneattribute.AddValue(pointData[2]);
                    GISFeature onefeature = new GISFeature(onepoint,oneattribute);
                    layer.AddFeature(onefeature);
                }
            }
            else if(ShapeType == SHAPETYPE.line)
            {
                layer.ShapeType = SHAPETYPE.line;
                int attributePosition = 6; //第一个属性在第六行
                int featureCount = int.Parse(lines[attributePosition - 1]); //获取线实体数量
                int pointCoposition = attributePosition + 1; //第一个线实体点数量数据位置
                int pointCount = int.Parse(lines[pointCoposition]); //获取第一个线实体的点数量
                for (int i = 0; i < featureCount; i++) //循环线实体数量的次数来读取
                {
                    List<GISLine> Lines = new List<GISLine>();
                    GISAttribute oneattribute = new GISAttribute();
                    oneattribute.AddValue(lines[attributePosition]); //储存线实体属性
                    List<GISVertex> vertexs = new List<GISVertex>(); //点数组临时储存点对坐标
                    for(int j = 1; j <= pointCount; j++) //循环点数量读取点
                    {
                        string[] pointData = lines[pointCoposition + j].Split(',');
                        GISVertex vertex = new GISVertex(double.Parse(pointData[0]), double.Parse(pointData[1]));
                        vertexs.Add(vertex);
                    }
                    Lines.Add(new GISLine(vertexs)); //保存该线实体的所有点数据到临时数组中
                    attributePosition = attributePosition + 1 + (pointCount + 1); //定位到下一个线实体属性位置
                    if (attributePosition < lines.Length) //如果已经读取完，则不再继续增加位置定位
                    {
                        pointCoposition = attributePosition + 1; //定位下一个线实体点数据的数量
                        pointCount = int.Parse(lines[pointCoposition]);
                    }
                    for (int k = 0; k < Lines.Count; k++) //循环添加临时数组中的线实体数据到layer中
                    {
                        GISFeature onefeature = new GISFeature(Lines[k], oneattribute);
                        layer.AddFeature(onefeature);
                    }
                }
            }
            else
            {
                layer.ShapeType = SHAPETYPE.polygon;
                int attributePosition = 6;
                int featureCount = int.Parse(lines[attributePosition - 1]);
                int pointCoPosition = attributePosition + 1;
                int pointCount = int.Parse(lines[pointCoPosition]);
                for (int i = 0; i < featureCount; i++)
                {
                    List<GISPolygon> polygons = new List<GISPolygon>();
                    GISAttribute oneattribute = new GISAttribute();
                    oneattribute.AddValue(lines[attributePosition]);
                    List<GISVertex> vertexs = new List<GISVertex>();
                    for(int j = 1; j <= pointCount; j++)
                    {
                        string[] pointData = lines[pointCoPosition + j].Split(',');
                        GISVertex vertex = new GISVertex(double.Parse(pointData[0]), double.Parse(pointData[1]));
                        vertexs.Add(vertex);
                    }
                    polygons.Add(new GISPolygon(vertexs));
                    attributePosition = attributePosition + 1 + (pointCount + 1);
                    if (attributePosition < lines.Length)
                    {
                        pointCoPosition = attributePosition + 1;
                        pointCount = int.Parse(lines[pointCoPosition]);
                    }
                    for(int k = 0; k < polygons.Count; k++)
                    {
                        GISFeature onefeature = new GISFeature(polygons[k], oneattribute);
                        layer.AddFeature(onefeature);
                    }
                }
            }
            return layer;
        }
    }

    public class GISShapefile
    {
        //记录头结构体
        [StructLayout(LayoutKind.Sequential, Pack = 4)]
        struct RecordHeader
        {
            public int RecordNumber;
            public int RecordLength;
            public int ShapeType;
        };

        static RecordHeader ReadRecordHeader(BinaryReader br) //读取记录头
        {
            byte[] buff = br.ReadBytes(Marshal.SizeOf(typeof(RecordHeader)));
            GCHandle handle = GCHandle.Alloc(buff, GCHandleType.Pinned);
            RecordHeader header = (RecordHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(RecordHeader));
            handle.Free();
            return header;
        }

        // 文件头结构体
        [StructLayout(LayoutKind.Sequential, Pack = 4)]
        struct ShapeFileHeader
        {
            public int Unused1, Unused2, Unused3, Unused4;
            public int Unused5, Unused6, Unused7, Unused8;
            public int ShapeType;
            public double Xmin;
            public double Ymin;
            public double Xmax;
            public double Ymax;
            public double Unused9, Unused10, Unused11, Unused12;
        };

        static ShapeFileHeader ReadFileHeader(BinaryReader br) //读取文件头
        {
            byte[] buff = br.ReadBytes(Marshal.SizeOf(typeof(ShapeFileHeader)));
            GCHandle handle = GCHandle.Alloc(buff, GCHandleType.Pinned);
            ShapeFileHeader header = (ShapeFileHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ShapeFileHeader));
            handle.Free();
            return header;
        }

        static int FromBigToLittle(int bigvalue)
        {
            byte[] bigbytes = new byte[4];
            GCHandle handle = GCHandle.Alloc(bigbytes, GCHandleType.Pinned);
            Marshal.StructureToPtr(bigvalue, handle.AddrOfPinnedObject(), false);
            handle.Free();
            byte b2 = bigbytes[2];
            byte b3 = bigbytes[3];
            bigbytes[3] = bigbytes[0];
            bigbytes[2] = bigbytes[1];
            bigbytes[1] = b2;
            bigbytes[0] = b3;
            return BitConverter.ToInt32(bigbytes, 0);
        }

        //读取dbf文件
        static DataTable ReadDBF(string dbffilename)
        {
            System.IO.FileInfo f = new FileInfo(dbffilename);
            DataSet ds = null;
            string constr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + f.DirectoryName + ";Extended Properties=DBASE III";
            using (OleDbConnection con = new OleDbConnection(constr))
            {
                var sql = "select * from " + f.Name;
                OleDbCommand cmd = new OleDbCommand(sql, con);
                con.Open();
                ds = new DataSet(); ;
                OleDbDataAdapter da = new OleDbDataAdapter(cmd);
                da.Fill(ds);
            }
            return ds.Tables[0];
        }

        //从给定的DataTable中读取字段信息，并返回一个GISField类型的列表
        static List<GISField> ReadFields(DataTable table)
        {
            List<GISField> fields = new List<GISField>();
            foreach (DataColumn column in table.Columns) //遍历表中的每一列
            {
                fields.Add(new GISField(column.DataType, column.ColumnName)); //存储列的数据类型和列名称
            }
            return fields;
        }

        static GISAttribute ReadAttribute(DataTable table, int RowIndex) //获取dbf表中的属性值
        {
            GISAttribute attribute = new GISAttribute();
            DataRow row = table.Rows[RowIndex]; //获取表的其中一行
            for (int i = 0; i < table.Columns.Count; i++) //遍历此行的每一列
            {
                attribute.AddValue(row[i]);
            }
            return attribute;
        }

        public static GISLayer ReadShapeFile(string shpfilename)
        {
            FileStream fsr = new FileStream(shpfilename, FileMode.Open); //打开文件
            BinaryReader br = new BinaryReader(fsr); //将文件以二进制流的形式存放于内存
            ShapeFileHeader sfh = ReadFileHeader(br); //读取文件头，存放在定义好的结构体中，sfh为结构体变量名
            SHAPETYPE ShapeType = (SHAPETYPE)Enum.Parse(typeof(SHAPETYPE), sfh.ShapeType.ToString()); //确定文件要素类型
            GISExtent extent = new GISExtent(sfh.Xmax, sfh.Xmin, sfh.Ymax, sfh.Ymin); //确定地图范围
            string dbffilename = shpfilename.Replace(".shp", ".dbf"); //确定该shp文件的.dbf文件名（将.shp替换为.dbf）
            DataTable table = ReadDBF(dbffilename); //读取dbf文件
            //将基本信息传入，包括图层名称（文件名）、要素类型、图层范围、属性字段列表
            GISLayer layer = new GISLayer(shpfilename, ShapeType, extent, ReadFields(table));
            int rowindex = 0;

            while (br.PeekChar() != -1)
            {
                RecordHeader rh = ReadRecordHeader(br); //读取记录头，存放在定义好的结构体中
                int RecordLength = FromBigToLittle(rh.RecordLength) * 2 - 4; //确定每条记录的长度
                byte[] RecordContent = br.ReadBytes(RecordLength); //读取指定长度的字节数到数组中
                if (ShapeType == SHAPETYPE.point)
                {
                    GISPoint onepoint = ReadPoint(RecordContent); //读点坐标数据
                    //储存点的整体信息，包括空间信息和属性信息
                    GISFeature onefeature = new GISFeature(onepoint, ReadAttribute(table, rowindex));
                    layer.AddFeature(onefeature); //添加一个要素到图层中
                }

                if (ShapeType == SHAPETYPE.line)
                {
                    List<GISLine> lines = ReadLines(RecordContent);
                    for (int i = 0; i < lines.Count; i++)
                    {
                        GISFeature onefeature = new GISFeature(lines[i], ReadAttribute(table, rowindex));
                        layer.AddFeature(onefeature);
                    }
                }

                if (ShapeType == SHAPETYPE.polygon)
                {
                    List<GISPolygon> polygons = ReadPolygons(RecordContent);
                    for (int i = 0; i < polygons.Count; i++)
                    {
                        GISFeature onefeature = new GISFeature(polygons[i], ReadAttribute(table, rowindex));
                        layer.AddFeature(onefeature);
                    }
                }
                rowindex++;
            }
            br.Close();
            fsr.Close();
            return layer;
        }

        //读取点要素信息
        static GISPoint ReadPoint(byte[] RecordContent)
        {
            double x = BitConverter.ToDouble(RecordContent, 0);
            double y = BitConverter.ToDouble(RecordContent, 8);
            return new GISPoint(new GISVertex(x, y));
        }

        //读取线要素信息
        static List<GISLine> ReadLines(byte[] RecordContent)
        {
            int N = BitConverter.ToInt32(RecordContent, 32); //线要素的数量
            int M = BitConverter.ToInt32(RecordContent, 36); //顶点数量
            int[] parts = new int[N + 1]; //用于存储每个部分的第一个顶点在顶点数组中的索引

            for (int i = 0; i < N; i++) //保存每个线实体的起始点位置到parts数组中
            {
                parts[i] = BitConverter.ToInt32(RecordContent, 40 + i * 4);
            }
            parts[N] = M;

            List<GISLine> lines = new List<GISLine>(); //一个GISLine只能保存一个线实体，因此需要数组保存所有线实体
            for (int i = 0; i < N; i++)
            {
                List<GISVertex> vertexs = new List<GISVertex>(); //点数组保存一个线实体中的所有点对
                for (int j = parts[i]; j < parts[i + 1]; j++) //循环保存一个点实体中的所有点对
                {
                    double x = BitConverter.ToDouble(RecordContent, 40 + N * 4 + j * 16);
                    double y = BitConverter.ToDouble(RecordContent, 40 + N * 4 + j * 16 + 8);
                    vertexs.Add(new GISVertex(x, y)); //储存到点数组中
                }
                lines.Add(new GISLine(vertexs)); //储存到线数组中
            }
            return lines;
        }

        //读取面要素信息
        static List<GISPolygon> ReadPolygons(byte[] RecordContent)
        {
            int N = BitConverter.ToInt32(RecordContent, 32);
            int M = BitConverter.ToInt32(RecordContent, 36);
            int[] parts = new int[N + 1];

            for (int i = 0; i < N; i++)
            {
                parts[i] = BitConverter.ToInt32(RecordContent, 40 + i * 4);
            }
            parts[N] = M;

            List<GISPolygon> polygons = new List<GISPolygon>();
            for (int i = 0; i < N; i++)
            {
                List<GISVertex> vertexs = new List<GISVertex>();
                for (int j = parts[i]; j < parts[i + 1]; j++)
                {
                    double x = BitConverter.ToDouble(RecordContent, 40 + N * 4 + j * 16);
                    double y = BitConverter.ToDouble(RecordContent, 40 + N * 4 + j * 16 + 8);
                    vertexs.Add(new GISVertex(x, y));
                }
                polygons.Add(new GISPolygon(vertexs));
            }
            return polygons;
        }

    }

    public class GISView
    {
        GISExtent CurrentMapExtent;
        Rectangle MapWindowSize;
        double MapMinX, MapMinY;
        int WinW, WinH;
        double MapW, MapH;
        double ScaleX, ScaleY;

        public GISView(GISExtent _extent, Rectangle _rectangle)
        {
            Update(_extent, _rectangle);
        }

        public void Update(GISExtent _extent, Rectangle _rectangle)
        {
            CurrentMapExtent = _extent;
            MapWindowSize = _rectangle;
            MapMinX = CurrentMapExtent.getMinX();
            MapMinY = CurrentMapExtent.getMinY();
            WinW = MapWindowSize.Width;
            WinH = MapWindowSize.Height;
            MapW = CurrentMapExtent.getWidth();
            MapH = CurrentMapExtent.getHeight();
            ScaleX = MapW / WinW;
            ScaleY = MapH / WinH;
        }

        public void ChangeView(GISMapActions action)
        {
            CurrentMapExtent.ChangeExtent(action);
            Update(CurrentMapExtent, MapWindowSize);
        }

        public void UpdateExtent(GISExtent extent)
        {
            CurrentMapExtent.CopyFrom(extent);
            Update(CurrentMapExtent, MapWindowSize);
        }

        public Point ToScreenPoint(GISVertex onevertex)
        {
            double ScreenX = (onevertex.x - MapMinX) / ScaleX;
            double ScreenY = WinH - (onevertex.y - MapMinY) / ScaleY;
            return new Point((int)ScreenX, (int)ScreenY);
        }

        public GISVertex ToMapVertex(Point point)
        {
            double MapX = ScaleX * point.X + MapMinX;
            double MapY = ScaleY * (WinH - point.Y) + MapMinY;
            return new GISVertex(MapX, MapY);
        }
    }


    public class GISFeature //定义了一个单位的要素，包含了要素的位置信息和属性信息
    {
        public GISSpatial spatialpart; //表示要素的空间部分
        public GISAttribute attributepart; //表示要素的属性部分

        public GISFeature(GISSpatial spatial, GISAttribute attribute)
        {
            spatialpart = spatial;
            attributepart = attribute;
        }

        public void draw(Graphics graphics, GISView view, bool DrawAttributeOrNot, int index)
        {
            spatialpart.draw(graphics, view);
            if (DrawAttributeOrNot)
                attributepart.draw(graphics, view, spatialpart.centroid, index);
        }

        public object getAttribute(int index) //用于获取该要素的属性值
        {
            return attributepart.GetValue(index);
        }

    }

    public abstract class GISSpatial
    {
        public GISVertex centroid;
        public GISExtent extent;

        public abstract void draw(Graphics graphics, GISView view);
    }

    public class GISExtent
    {
        public GISVertex upright;
        public GISVertex bottomleft;

        public GISExtent(GISVertex _bottomleft, GISVertex _upright)
        {
            upright = _upright;
            bottomleft = _bottomleft;
        }

        public GISExtent(double x1, double x2, double y1, double y2)
        {
            upright = new GISVertex(Math.Max(x1, x2), Math.Max(y1, y2));
            bottomleft = new GISVertex(Math.Min(x1, x2), Math.Min(y1, y2));
        }

        public void CopyFrom(GISExtent extent)
        {
            upright.CopyFrom(extent.upright);
            bottomleft.CopyFrom(extent.bottomleft);
        }

        double ZoomingFactor = 2;
        double MovingFactor = 0.25;

        public void ChangeExtent(GISMapActions action)
        {
            double newminx = bottomleft.x, newminy = bottomleft.y,
                newmaxx = upright.x, newmaxy = upright.y;
            switch (action)
            {
                case GISMapActions.zoomin:
                    newminx = ((getMinX() + getMaxX()) - getWidth() / ZoomingFactor) / 2;
                    newminy = ((getMinY() + getMaxY()) - getHeight() / ZoomingFactor) / 2;
                    newmaxx = ((getMinX() + getMaxX()) + getWidth() / ZoomingFactor) / 2;
                    newmaxy = ((getMinY() + getMaxY()) + getHeight() / ZoomingFactor) / 2;
                    break;
                case GISMapActions.zoomout:
                    newminx = ((getMinX() + getMaxX()) - getWidth() * ZoomingFactor) / 2;
                    newminy = ((getMinY() + getMaxY()) - getHeight() * ZoomingFactor) / 2;
                    newmaxx = ((getMinX() + getMaxX()) + getWidth() * ZoomingFactor) / 2;
                    newmaxy = ((getMinY() + getMaxY()) + getHeight() * ZoomingFactor) / 2;
                    break;
                case GISMapActions.moveup:
                    newminy = getMinY() - getHeight() * MovingFactor;
                    newmaxy = getMaxY() - getHeight() * MovingFactor;
                    break;
                case GISMapActions.movedown:
                    newminy = getMinY() + getHeight() * MovingFactor;
                    newmaxy = getMaxY() + getHeight() * MovingFactor;
                    break;
                case GISMapActions.moveleft:
                    newminx = getMinX() + getWidth() * MovingFactor;
                    newmaxx = getMaxX() + getWidth() * MovingFactor;
                    break;
                case GISMapActions.moveright:
                    newminx = getMinX() - getWidth() * MovingFactor;
                    newmaxx = getMaxX() - getWidth() * MovingFactor;
                    break;
            }
            upright.x = newmaxx;
            upright.y = newmaxy;
            bottomleft.x = newminx;
            bottomleft.y = newminy;
        }

        public double getMinX()
        {
            return bottomleft.x;
        }

        public double getMaxX()
        {
            return upright.x;
        }

        public double getMinY()
        {
            return bottomleft.y;
        }

        public double getMaxY()
        {
            return upright.y;
        }

        public double getWidth()
        {
            return upright.x - bottomleft.x;
        }

        public double getHeight()
        {
            return upright.y - bottomleft.y;
        }
    }


    public class GISVertex
    {
        public double x;
        public double y;

        public GISVertex(double _x, double _y)
        {
            x = _x;
            y = _y;
        }

        public double Distance(GISVertex anothervertex)
        {
            return Math.Sqrt((x - anothervertex.x) * (x - anothervertex.x) + (y - anothervertex.y) * (y - anothervertex.y));
        }

        public void CopyFrom(GISVertex v)
        {
            x = v.x;
            y = v.y;
        }
    }



    public class GISPoint : GISSpatial
    {
        public GISPoint(GISVertex onevertex)
        {
            centroid = onevertex;
            extent = new GISExtent(onevertex, onevertex);
        }

        public override void draw(Graphics graphics, GISView view)
        {
            Point screenpoint = view.ToScreenPoint(centroid);
            graphics.FillEllipse(new SolidBrush(Color.Red),
                new Rectangle(screenpoint.X - 3, screenpoint.Y - 3, 6, 6));
        }

        public double Distance(GISVertex anothervertex)
        {
            return centroid.Distance(anothervertex);
        }
    }

    public class GISLine : GISSpatial
    {
        public List<GISVertex> Vertexes;
        public double Length;
        public GISLine(List<GISVertex> _vertexes)
        {
            Vertexes = _vertexes;
            centroid = GISTools.CalculateCentroid(_vertexes);
            extent = GISTools.CalculateExtent(_vertexes);
            Length = GISTools.CalculateLength(_vertexes);
        }
        public override void draw(Graphics graphics, GISView view)
        {
            Point[] points = GISTools.GetScreenPoints(Vertexes, view);
            graphics.DrawLines(new Pen(Color.Red, 2), points);
        }
        public GISVertex FromNode()
        {
            return Vertexes[0];
        }
        public GISVertex ToNode()
        {
            return Vertexes[Vertexes.Count - 1];
        }

    }
    public class GISPolygon : GISSpatial
    {
        public List<GISVertex> Vertexes;
        public double Area;
        public GISPolygon(List<GISVertex> _vertexes)
        {
            Vertexes = _vertexes;
            centroid = GISTools.CalculateCentroid(_vertexes);
            extent = GISTools.CalculateExtent(_vertexes);
            Area = GISTools.CalculateArea(_vertexes);
        }
        public override void draw(Graphics graphics, GISView view)
        {
            Point[] points = GISTools.GetScreenPoints(Vertexes, view);
            graphics.FillPolygon(new SolidBrush(Color.Yellow), points);
            graphics.DrawPolygon(new Pen(Color.White, 2), points);
        }
    }

    public class GISAttribute
    {
        ArrayList values = new ArrayList(); //用于储存属性值

        public void AddValue(object o) //用于将一个值添加到values列表中
        {
            values.Add(o);
        }

        public object GetValue(int index) //用于从values列表中获取指定索引位置的值
        {
            return values[index];
        }


        public void draw(Graphics graphics, GISView view, GISVertex location, int index)
        {
            Point screenpoint = view.ToScreenPoint(location);
            graphics.DrawString(values[index].ToString(),
                new Font("宋体", 20),
                new SolidBrush(Color.Green),
                new PointF(screenpoint.X, screenpoint.Y));
        }
    }
}